
const {
    wxpusher,
} = require('./ti_config');

const {
    logger,
    sleep,
    initPage2,
    closeBrowser,
    randBetween,
    httpPost,
    avoidNoticeFreq,
    waitOtherWorker,
    updateErrorTimes,
    closeRun,
    lpush,
} = require('./util');

const {
    readTask,
} = require('./ti_logic_read_task');

//全局捕获错误
process.on('unhandledRejection', error => {
    //...不处理处理...
});

let openSerials = [];//需要关注的规格

//每30秒重新拉取任务列表
(async () => {
    while (1) {
        const tasks = await readTask();
        if (!tasks) continue;
        const tmpSerials = [];
        for (const task of tasks) {
            if (task.status != 1) continue;
            tmpSerials.push(task.serial);
        }
        openSerials = tmpSerials;
        await sleep(30000);
    }
})();

//用随机数模拟页面滚动以及鼠标滑动
const randomScrollAndMouseMove = async page => {
    const x1 = randBetween(400, 1600);
    const y1 = randBetween(0, 300);
    const wait1 = randBetween(60, 120);
    const scrollY1 = randBetween(200, 500);
    logger('滚动页面到输入框处，并模拟鼠标滑动', x1, y1, wait1, scrollY1);
    await page.mouse.move(x1, y1, {steps:wait1});
    await page.evaluate(scrollY => {
        window.scrollTo(0, scrollY);
    }, scrollY1);
    const x2 = randBetween(200, 1500);
    const y2 = randBetween(300, 600);
    const wait2 = randBetween(60, 120);
    const scrollY2 = randBetween(500, 700);
    logger('模拟鼠标滑动', x2, y2, wait2, scrollY2);
    await page.mouse.move(x2, y2, {steps:wait2});
    await sleep(1000);
    await page.evaluate(scrollY => {
        window.scrollTo(0, scrollY);
    }, scrollY2);
}

const randomMoveAndClick = async page => {
    //鼠标随机移动4-6个地方
    const mouseMoveNum = randBetween(4, 6);
    logger('鼠标随机移动', mouseMoveNum, '次');
    for (let i=0; i<mouseMoveNum; i++) {
        const x = 10 + randBetween(100, 1700);
        const y = 110 + randBetween(200, 800);
        const steps = randBetween(30, 60);
        await page.mouse.move(x, y, {steps});
        await sleep(randBetween(200, 700));
    }

    logger('鼠标移动到输入框并点击');
    const targetInput = await page.$('ti-input');
    const box = await targetInput.boundingBox();
    const x1 = box.x + (box.width/2) - 3;
    const y1 = box.y + (box.height/2) - 2;
    const steps1 = randBetween(30, 60);
    await page.mouse.move(x1, y1, {steps:steps1});
    await page.mouse.click(x1, y1, {delay:200});
    await sleep(1000);
    logger('鼠标移出输入框并点击');
    const x2 = x1 - randBetween(100, 200);
    const y2 = y1 - randBetween(10, 200);
    const steps2 = randBetween(30, 60);
    await page.mouse.move(x2, y2, {steps:steps2});
    await page.mouse.click(x2, y2, {delay:100});
    await sleep(2000);
}

//程序主流程
(async () => {

    const page = await initPage2();
    logger('启动浏览器');
    try {
        await page.goto('https://www.ti.com.cn/zh-cn/ordering-resources/buying-tools/quick-add-to-cart.html', {
        waitUntil: 'networkidle2'  // 网络空闲说明已加载完毕
    });
        await page.waitForSelector('ti-input');
    } catch(e) {
        logger('打开快速下单页失败，将重启浏览器');
        await closeBrowser();
        await sleep(5000);
        return process.exit(1);
    }
    await randomScrollAndMouseMove(page);

    let timeoutCount = 0;
    let counter = 0;
    while (1) {
        logger('第', ++counter, '轮');

        //如果有其他进程在跑，等待
        //await waitOtherWorker();

        //鼠标随机移动和点击，有可能被卡住。如果超过n秒未完成，则强制跳过
        await Promise.race([
            randomMoveAndClick(page),
            sleep(20000),
        ]);

        logger('查询库存');
        try {
            const ret = await page.evaluate(async (serialStr) => {
                const ajax = () => {
                    return new Promise(resolve => {
                        const timer = setTimeout(() => {
                            resolve('timeout');
                        }, 15000);
                        const xhr = new XMLHttpRequest();
                        xhr.open('post', 'https://www.ti.com.cn/storeservices/cart/inventory', true);
                        xhr.setRequestHeader('Content-Type', 'application/json');
                        xhr.onreadystatechange = function(){
                            if (xhr.readyState == 4) {
                                if (xhr.status == 200) {
                                    resolve(xhr.responseText);
                                } else {
                                    resolve(xhr.statusText);
                                }
                                clearTimeout(timer);
                            }
                        };
                        xhr.send(serialStr);
                    });
                }
                const ret = await ajax();
                return ret;
            }, JSON.stringify(openSerials.sort(() => 0.5-Math.random())));

            logger('查询结果', ret);
            if (ret[0] == '{') {
                timeoutCount = 0;
                const retJson = JSON.parse(ret);
                let found = 0;
                for (const v of retJson.opn_list) {
                    if (v.purchase_flag == 'Y' && v.quantity >= 250) {
                        found = 1;
                        const msg = `规格 ${v.orderable_number} 发现有 ${v.quantity} 库存可以下单`;
                        logger(msg);

                        //如果对应规格最近1小时内报告超过3次，则不再告警，避免信息轰炸
                        if (avoidNoticeFreq(v.orderable_number)) {
                            try {
                                //推送到队列，等待自动下单程序执行
                                await lpush('ti_worker_found', v.orderable_number);

                                //推送消息
                                await httpPost('http://wxpusher.zjiecode.com/api/send/message', JSON.stringify({
                                    appToken: wxpusher.appToken,
                                    content: msg,
                                    contentType: 1,
                                    uids: wxpusher.uids,
                                }), 'application/json');
                            } catch(e) {
                                logger(e);
                            }
                        }
                    }
                }
                if (!found) {
                    logger('本轮未检测到有库存');
                    await sleep(2000);
                }
            } else {
                //返回内容不是JSON，可能是被拦截了，等n秒后再重新请求
                await sleep(2000);
                timeoutCount++;
                await updateErrorTimes(timeoutCount);
                //连续n次timeout，退出重启浏览器
                if (timeoutCount >= 1) {
                    break;
                }
            }
        } catch(e) {
            logger('查询出错', e);
            await sleep(2000);
            continue;
        }
    }

    await closeRun();
    logger('失败过多，关闭浏览器');
    await closeBrowser();
    process.exit(1);

})();

